﻿/*******************************************************************************
Copyright (c) 2011-2013, PKStudio

http://pkstudio.org

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/
using System;
using System.Diagnostics;
using System.Drawing;

namespace PKEngine
{
	/// <summary>
	/// PKButtonLabel for engine.
	/// </summary>
	public class PKButtonLabel : PKMenuItemLabel, IPKMouseResponder
	{
		#region Private Fields
		private bool isClicked;
		private int priority;
		#endregion

		#region Public Properties
		/// <summary>
		/// Priority property of PKButton.
		/// </summary>
		public int Priority
		{
			get
			{
				return this.priority;
			}
			set
			{
				this.priority = value;
				if (this.IsRunning)
				{
					PKMouseDispatcher.SharedDispatcher.SetPriority(this, value);
				}
			}
		}
		#endregion

		#region Initialization
		public static PKButtonLabel ButtonMake(IPKLabel label)
		{
			return new PKButtonLabel().Init(label) as PKButtonLabel;
		}

		public static PKButtonLabel ButtonMake(IPKLabel label, EventDelegate targetDelegate)
		{
			return new PKButtonLabel().Init(label, targetDelegate) as PKButtonLabel;
		}

		public override PKMenuItemLabel Init(IPKLabel label)
		{
			return this.Init(label, null);
		}

		public override PKMenuItemLabel Init(IPKLabel label, EventDelegate targetDelegate)
		{
			base.Init(label, targetDelegate);

			this.isClicked = false;
			this.priority = 0;

			return this;
		}
		#endregion

		#region Public Method
		public override void OnEnter()
		{
			PKMouseDispatcher.SharedDispatcher.AddHandler(this, this.Priority, true);
			base.OnEnter();
		}

		public override void OnExit()
		{
			if (isClicked)
			{
				this.Unselect();
				isClicked = false;
			}

			PKMouseDispatcher.SharedDispatcher.RemoveHandler(this);
			base.OnExit();
		}

		public virtual bool MouseDown(PKMouseEvent mouse)
		{
			if (isClicked || !this.ContainsMousePos(mouse))
			{
				return false;
			}

			for (PKNode p = Parent; p != null; p = p.Parent)
			{
				if (!p.IsVisible)
				{
					return false;
				}
			}

			this.Select();
			isClicked = true;
			return true;
		}

		public virtual void MouseDrag(PKMouseEvent mouse)
		{
			Debug.Assert(isClicked);

			if (this.ContainsMousePos(mouse))
			{
				this.Select();
			}
			else
			{
				this.Unselect();
			}
		}

		public virtual void MouseUp(PKMouseEvent mouse)
		{
			Debug.Assert(isClicked);

			if (this.ContainsMousePos(mouse))
			{
				this.Activate();
			}
			isClicked = false;
		}

		public virtual bool MouseMove(PKMouseEvent mouse)
		{
			// Override me.
			return true;
		}
		#endregion

		#region Protected Methods
		protected virtual bool ContainsMousePos(PKMouseEvent mouse)
		{
			if (!IsVisible || !IsEnabled)
			{
				return false;
			}
			return BoundingBox.Contains(mouse.CurrentPos);
		}
		#endregion
	}

	/// <summary>
	/// PKButtonSprite for engine.
	/// </summary>
	public class PKButtonSprite : PKMenuItemSprite, IPKMouseResponder
	{
		#region Private Fields
		private bool isClicked;
		private int priority;
		#endregion

		#region Public Properties
		/// <summary>
		/// Priority property of PKButton.
		/// </summary>
		public int Priority
		{
			get
			{
				return this.priority;
			}
			set
			{
				this.priority = value;
				if (this.IsRunning)
				{
					PKMouseDispatcher.SharedDispatcher.SetPriority(this, value);
				}
			}
		}
		#endregion

		#region Initialization
		public static PKButtonSprite ButtonMake(PKSprite sprite)
		{
			return new PKButtonSprite().Init(sprite) as PKButtonSprite;
		}

		public static PKButtonSprite ButtonMake(PKSprite sprite, EventDelegate targetDelegate)
		{
			return new PKButtonSprite().Init(sprite, targetDelegate) as PKButtonSprite;
		}

		public static PKButtonSprite ButtonMake(PKSurface surface)
		{
			return new PKButtonSprite().Init(surface) as PKButtonSprite;
		}

		public static PKButtonSprite ButtonMake(PKSurface surface, Rectangle rect)
		{
			return new PKButtonSprite().Init(surface, rect) as PKButtonSprite;
		}

		public static PKButtonSprite ButtonMake(string fileName)
		{
			return new PKButtonSprite().Init(fileName) as PKButtonSprite;
		}

		public static PKButtonSprite ButtonMake(string fileName, Rectangle rect)
		{
			return new PKButtonSprite().Init(fileName, rect) as PKButtonSprite;
		}

		public override PKMenuItemSprite Init(PKSprite sprite)
		{
			return this.Init(sprite, null);
		}

		public override PKMenuItemSprite Init(PKSprite sprite, EventDelegate targetDelegate)
		{
			base.Init(sprite, targetDelegate);

			this.isClicked = false;
			this.priority = 0;

			return this;
		}

		public override PKMenuItemSprite Init(PKSurface surface)
		{
			return this.Init(new PKSprite(surface), null);
		}

		public override PKMenuItemSprite Init(PKSurface surface, Rectangle rect)
		{
			return this.Init(new PKSprite(surface, rect), null);
		}

		public override PKMenuItemSprite Init(string fileName)
		{
			return this.Init(new PKSprite(fileName), null);
		}

		public override PKMenuItemSprite Init(string fileName, Rectangle rect)
		{
			return this.Init(new PKSprite(fileName, rect), null);
		}
		#endregion

		#region Public Method
		public override void OnEnter()
		{
			PKMouseDispatcher.SharedDispatcher.AddHandler(this, this.Priority, true);
			base.OnEnter();
		}

		public override void OnExit()
		{
			if (isClicked)
			{
				this.Unselect();
				isClicked = false;
			}

			PKMouseDispatcher.SharedDispatcher.RemoveHandler(this);
			base.OnExit();
		}

		public virtual bool MouseDown(PKMouseEvent mouse)
		{
			if (isClicked || !this.ContainsMousePos(mouse))
			{
				return false;
			}

			for (PKNode p = Parent; p != null; p = p.Parent)
			{
				if (!p.IsVisible)
				{
					return false;
				}
			}

			this.Select();
			isClicked = true;
			return true;
		}

		public virtual void MouseDrag(PKMouseEvent mouse)
		{
			Debug.Assert(isClicked);

			if (this.ContainsMousePos(mouse))
			{
				this.Select();
			}
			else
			{
				this.Unselect();
			}
		}

		public virtual void MouseUp(PKMouseEvent mouse)
		{
			Debug.Assert(isClicked);

			if (this.ContainsMousePos(mouse))
			{
				this.Activate();
			}
			isClicked = false;
		}

		public virtual bool MouseMove(PKMouseEvent mouse)
		{
			// Override me.
			return true;
		}
		#endregion

		#region Protected Methods
		protected virtual bool ContainsMousePos(PKMouseEvent mouse)
		{
			if (!IsVisible || !IsEnabled)
			{
				return false;
			}
			return BoundingBox.Contains(mouse.CurrentPos);
		}
		#endregion
	}

	/// <summary>
	/// PKButtonSpriteSet for engine.
	/// </summary>
	public class PKButtonSpriteSet : PKMenuItemSpriteSet, IPKMouseResponder
	{
		#region Private Fields
		private bool isClicked;
		private int priority;
		#endregion

		#region Public Properties
		/// <summary>
		/// Priority property of PKButton.
		/// </summary>
		public int Priority
		{
			get
			{
				return this.priority;
			}
			set
			{
				this.priority = value;
				if (this.IsRunning)
				{
					PKMouseDispatcher.SharedDispatcher.SetPriority(this, value);
				}
			}
		}
		#endregion

		#region Initialization
		public static PKButtonSpriteSet ButtonMake(PKSprite normalSprite, PKSprite disabledSprite, PKSprite selectedSprite)
		{
			return new PKButtonSpriteSet().Init(normalSprite, disabledSprite, selectedSprite) as PKButtonSpriteSet;
		}

		public static PKButtonSpriteSet ButtonMake(PKSprite normalSprite, PKSprite disabledSprite, PKSprite selectedSprite, EventDelegate targetDelegate)
		{
			return new PKButtonSpriteSet().Init(normalSprite, disabledSprite, selectedSprite, targetDelegate) as PKButtonSpriteSet;
		}

		public static PKButtonSpriteSet ButtonMake(string fileNormal)
		{
			return new PKButtonSpriteSet().Init(fileNormal) as PKButtonSpriteSet;
		}

		public static PKButtonSpriteSet ButtonMake(string fileNormal, string fileDisabled)
		{
			return new PKButtonSpriteSet().Init(fileNormal, fileDisabled) as PKButtonSpriteSet;
		}

		public static PKButtonSpriteSet ButtonMake(string fileNormal, string fileDisabled, string fileSelected)
		{
			return new PKButtonSpriteSet().Init(fileNormal, fileDisabled, fileSelected) as PKButtonSpriteSet;
		}

		public override PKMenuItemSpriteSet Init(PKSprite normalSprite, PKSprite disabledSprite, PKSprite selectedSprite)
		{
			return this.Init(normalSprite, disabledSprite, selectedSprite, null);
		}

		public override PKMenuItemSpriteSet Init(PKSprite normalSprite, PKSprite disabledSprite, PKSprite selectedSprite, EventDelegate targetDelegate)
		{
			base.Init(normalSprite, disabledSprite, selectedSprite, targetDelegate);

			this.isClicked = false;
			this.priority = 0;

			return this;
		}

		public override PKMenuItemSpriteSet Init(string fileNormal)
		{
			return this.Init(new PKSprite(fileNormal), null, null, null);
		}

		public override PKMenuItemSpriteSet Init(string fileNormal, string fileDisabled)
		{
			return this.Init(new PKSprite(fileNormal), new PKSprite(fileDisabled), null, null);
		}

		public override PKMenuItemSpriteSet Init(string fileNormal, string fileDisabled, string fileSelected)
		{
			return this.Init(new PKSprite(fileNormal), new PKSprite(fileDisabled), new PKSprite(fileSelected), null);
		}
		#endregion

		#region Public Method
		public override void OnEnter()
		{
			PKMouseDispatcher.SharedDispatcher.AddHandler(this, this.Priority, true);
			base.OnEnter();
		}

		public override void OnExit()
		{
			if (isClicked)
			{
				this.Unselect();
				isClicked = false;
			}

			PKMouseDispatcher.SharedDispatcher.RemoveHandler(this);
			base.OnExit();
		}

		public virtual bool MouseDown(PKMouseEvent mouse)
		{
			if (isClicked || !this.ContainsMousePos(mouse))
			{
				return false;
			}

			for (PKNode p = Parent; p != null; p = p.Parent)
			{
				if (!p.IsVisible)
				{
					return false;
				}
			}

			this.Select();
			isClicked = true;
			return true;
		}

		public virtual void MouseDrag(PKMouseEvent mouse)
		{
			Debug.Assert(isClicked);

			if (this.ContainsMousePos(mouse))
			{
				this.Select();
			}
			else
			{
				this.Unselect();
			}
		}

		public virtual void MouseUp(PKMouseEvent mouse)
		{
			Debug.Assert(isClicked);

			if (this.ContainsMousePos(mouse))
			{
				this.Activate();
			}
			isClicked = false;
		}

		public virtual bool MouseMove(PKMouseEvent mouse)
		{
			// Override me.
			return true;
		}
		#endregion

		#region Protected Methods
		protected virtual bool ContainsMousePos(PKMouseEvent mouse)
		{
			if (!IsVisible || !IsEnabled)
			{
				return false;
			}
			return BoundingBox.Contains(mouse.CurrentPos);
		}
		#endregion
	}
}
